package org.lhl

import javafx.application.Platform
import javafx.event.ActionEvent
import javafx.fxml.FXML
import javafx.fxml.Initializable
import javafx.scene.Node
import javafx.scene.control.*
import javafx.scene.layout.HBox
import javafx.stage.DirectoryChooser
import java.io.File
import java.net.URL
import java.util.*

private var initDir: File? = null

class Controller : Initializable {

    @FXML
    private lateinit var dirText: Label

    @FXML
    private lateinit var hBox1: HBox

    @FXML
    private lateinit var fileCountText: Label

    @FXML
    private lateinit var progressText: Label

    @FXML
    private lateinit var keyTextField: TextField

    @FXML
    private lateinit var ivTextField: TextField

    @FXML
    private lateinit var progressBar: ProgressBar


    @FXML
    private lateinit var btnEncrypt: Button

    @FXML
    private lateinit var btnDecrypt: Button

    private lateinit var mFiles: List<File>

    private var readFileCountThread: Thread? = null

    @FXML
    fun chooseDir(event: ActionEvent) {

        if (readFileCountThread?.isAlive == true)
            readFileCountThread?.interrupt()
        hBox1.isVisible = false
        progressBar.isVisible = false
        dirText.text = ""
        fileCountText.text = ""
        progressText.text = ""
        val window = (event.source as Node).scene.window
        val dirChooser = DirectoryChooser()
        dirChooser.title = "选择切片目录"
        dirChooser.initialDirectory = initDir
        val file = dirChooser.showDialog(window)
        ?: //            "请选择切片目录".alert(false)
        return
        initDir = file
        hBox1.isVisible = true
        dirText.text = file.absolutePath
        fileCountText.text = "正在读取文件个数，请稍等.."
        btnEncrypt.isVisible = false
        btnDecrypt.isVisible = false
        readFileCountThread = Thread {
            mFiles = FileUtils.listFilesInDir(file, true).filter { it.isFile }
            val ret = Main.INSTANCE.CRYPTION_AES_CFB_INIT()
            Platform.runLater {
                btnEncrypt.isVisible = true
                btnDecrypt.isVisible = true
                fileCountText.text = "文件个数：${mFiles.size}  ，机器码结果：$ret"
            }
        }.apply { start() }

    }

    @FXML
    fun startEncrypt(event: ActionEvent) {
        if (mFiles.isNullOrEmpty()) {
//            "没有文件".alert()
            return
        }
        val key = keyTextField.text.trim()
        val iv = ivTextField.text.trim()
        if (key.isNotEmpty() && iv.isNotEmpty()) {
            "设置key=$key  iv=$iv".p()
            Main.INSTANCE.SET_AES_CFB_KEY_IV(key, iv)
        } else
            Main.INSTANCE.CRYPTION_AES_CFB_INIT()
        progressBar.progress = 0.0
        progressBar.isVisible = true
        Thread {
            try {
                for (i in mFiles.indices) {
                    val file = mFiles[i]
                    Platform.runLater {
                        progressText.text = "正在加密第${i + 1}个文件${file.name}.."
                        progressBar.progress = 1.0 * (i + 1) / mFiles.size
                    }
                    val content = FileIOUtils.readFile2BytesByStream(file).toHexString()
                    val encrypt = Main.INSTANCE.AES_CFB_ENCRYPT_STRING(content, content.length) ?: kotlin.run {
                        Platform.runLater { "加密第${i + 1}个文件出错：${file.name}".alert() }
                        return@Thread
                    }
                    FileIOUtils.writeFileFromString(file, encrypt)
                    // 文件名 00123_00456
                    val fileName = file.nameWithoutExtension
                    // 分割获取xy
                    val names = fileName.split("_").apply { if (this.size != 2) error("文件名称不对_：$fileName") }
                    // x值去前0 + '1'
                    val x = names[0].remove0().toIntOrNull()?.let { it + '1'.toInt() } ?: error("文件名称不对x：$fileName")
                    // y值去前0 + '1'
                    val y = names[1].remove0().toIntOrNull()?.let { it + '1'.toInt() } ?: error("文件名称不对y：$fileName")
                    // 拼接明文文件名
                    val origin = "${y}-${x}"
                    // 明文加密 -> 转16进制byte数组 -> 单个byte + '2' -> 转回16进制String
                    val en = Main.INSTANCE.AES_CFB_ENCRYPT_STRING(origin, origin.length)
                    val newFileName = en.toHexByteArray()?.toHexString('2'.toInt())?.toUpperCase() ?: kotlin.run {
                        Platform.runLater { "加密第${i + 1}个文件名称出错：$fileName".alert() }
                        return@Thread
                    }
                    val b = file.renameTo(File(file.parent + "/" + newFileName))
                    if (!b) error("文件重命名出错：原=${fileName} ，新=${newFileName}")
                }
            } catch (e: Exception) {
                e.printStackTrace()
                Platform.runLater { progressText.text = "加密出错：$e" }
                return@Thread
            }
            Platform.runLater { progressText.text = "加密完成！" }

        }.start()


    }

    @FXML
    fun startDecrypt(event: ActionEvent) {

        if (mFiles.isNullOrEmpty()) {
//            "没有文件".alert()
            return
        }

        val key = keyTextField.text.trim()
        val iv = ivTextField.text.trim()
        if (key.isNotEmpty() && iv.isNotEmpty()) {
            Main.INSTANCE.SET_AES_CFB_KEY_IV(key, iv)
        } else {
            Main.INSTANCE.CRYPTION_AES_CFB_INIT()
        }
        progressBar.progress = 0.0
        progressBar.isVisible = true

        Thread {
            try {
                for (i in mFiles.indices) {
                    val file = mFiles[i]
                    Platform.runLater {
                        progressText.text = "正在解密第${i + 1}个文件${file.name}.."
                        progressBar.progress = 1.0 * (i + 1) / mFiles.size
                    }
                    val content = FileIOUtils.readFile2String(file)
//                    val content = FileIOUtils.readFile2BytesByStream(file).toHexString()
                    val decrypt = Main.INSTANCE.AES_CFB_DECRYPT_STRING(content, content.length).toHexByteArray() ?: kotlin.run {
                        Platform.runLater { "解密第${i + 1}个文件出错: ${file.name}".alert() }
                        return@Thread
                    }
                    FileIOUtils.writeFileFromBytesByStream(file, decrypt)
                    val b = file.renameTo(File(file.absolutePath + ".png"))
                    if (!b) error("文件重命名出错：原=${file.name} ")
                }
            } catch (e: Exception) {
                e.printStackTrace()
                Platform.runLater { progressText.text = "解密出错：$e" }
                return@Thread
            }
            Platform.runLater { progressText.text = "解密完成！" }
        }.start()
    }

    private fun String.toHexByteArray(): ByteArray? {
        val sb = StringBuilder()
        val bytes = ByteArray(this.length / 2)
        var index = 0
        this.forEach {
            sb.append(it)
            if (sb.length == 2) {
                bytes[index] = sb.toString().toInt(16).toByte()
                index++
                sb.clear()
            }
        }
        return bytes
    }

    private fun ByteArray.toHexString(add: Int = 0): String {
        return this.joinToString("") { ((it + add) and 0xff).toString(16).add0() }
    }

    override fun initialize(location: URL?, resources: ResourceBundle?) {
        hBox1.isVisible = false
        progressBar.isVisible = false
    }

}

fun String.alert(isExit: Boolean = false) {
    val alert = Alert(Alert.AlertType.INFORMATION)
    alert.title = "提示"
    alert.headerText = null
    alert.contentText = this
    alert.showAndWait()
    if (isExit)
        Platform.exit()
}

fun Any.p() = println(this)

fun String.add0(): String {
    return if (this.length < 2) "0$this" else this
}

fun String.remove0(): String {
    var s = this
    while (s.length > 1 && s.startsWith("0")) {
        s = s.removePrefix("0")
    }
    return s
}